// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "GameFeatureAction_WorldActionBase.h"
#include "Abilities/GameplayAbility.h"
#include "AbilitySystem/LyraAbilitySet.h"

#include "GameFeatureAction_AddAbilities.generated.h"

struct FWorldContext;
class UInputAction;
class UAttributeSet;
class UDataTable;
struct FComponentRequestHandle;
class ULyraAbilitySet;

/**
 * 能力授予结构体
 */
USTRUCT(BlueprintType)
struct FLyraAbilityGrant
{
	GENERATED_BODY()

	// 要授予的能力类型
	UPROPERTY(EditAnywhere, BlueprintReadOnly, meta=(AssetBundles="Client,Server"))
	TSoftClassPtr<UGameplayAbility> AbilityType;

	// 要绑定能力的输入动作（可选，可留空）
// 	UPROPERTY(EditAnywhere, BlueprintReadOnly)
// 	TSoftObjectPtr<UInputAction> InputAction;
};

/**
 * 属性集授予结构体
 */
USTRUCT(BlueprintType)
struct FLyraAttributeSetGrant
{
	GENERATED_BODY()

	// 要授予的属性集
	UPROPERTY(EditAnywhere, BlueprintReadOnly, meta=(AssetBundles="Client,Server"))
	TSoftClassPtr<UAttributeSet> AttributeSetType;

	// 用于初始化属性的数据表引用（可选，可留空）
	UPROPERTY(EditAnywhere, BlueprintReadOnly, meta=(AssetBundles="Client,Server"))
	TSoftObjectPtr<UDataTable> InitializationData;
};

/**
 * 游戏特性能力条目结构体
 */
USTRUCT()
struct FGameFeatureAbilitiesEntry
{
	GENERATED_BODY()

	// 要添加能力的基础Actor类
	UPROPERTY(EditAnywhere, Category="Abilities")
	TSoftClassPtr<AActor> ActorClass; // 目标Actor类

	// 要授予给指定类Actor的能力列表
	UPROPERTY(EditAnywhere, Category="Abilities")
	TArray<FLyraAbilityGrant> GrantedAbilities; // 授予的能力列表

	// 要授予给指定类Actor的属性集列表
	UPROPERTY(EditAnywhere, Category="Attributes")
	TArray<FLyraAttributeSetGrant> GrantedAttributes; // 授予的属性集列表

	// 要授予给指定类Actor的能力集列表
	UPROPERTY(EditAnywhere, Category="Attributes", meta=(AssetBundles="Client,Server"))
	TArray<TSoftObjectPtr<const ULyraAbilitySet>> GrantedAbilitySets; // 授予的能力集列表
};

//////////////////////////////////////////////////////////////////////
// UGameFeatureAction_AddAbilities

/**
 * 负责向指定类型的Actor授予能力（和属性）的GameFeatureAction
 */
UCLASS(MinimalAPI, meta = (DisplayName = "Add Abilities"))
class UGameFeatureAction_AddAbilities final : public UGameFeatureAction_WorldActionBase
{
	GENERATED_BODY()

public:
	//~ 开始 UGameFeatureAction 接口
	virtual void OnGameFeatureActivating(FGameFeatureActivatingContext& Context) override; // 游戏特性激活时调用
	virtual void OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& Context) override; // 游戏特性停用时调用
	//~ 结束 UGameFeatureAction 接口

	//~ 开始 UObject 接口
#if WITH_EDITOR
	virtual EDataValidationResult IsDataValid(class FDataValidationContext& Context) const override; // 数据验证
#endif
	//~ 结束 UObject 接口

	/** 能力列表配置 */
	UPROPERTY(EditAnywhere, Category="Abilities", meta=(TitleProperty="ActorClass", ShowOnlyInnerProperties))
	TArray<FGameFeatureAbilitiesEntry> AbilitiesList; // 能力配置条目列表

private:
	/**
	 * Actor扩展数据结构
	 */
	struct FActorExtensions
	{
		TArray<FGameplayAbilitySpecHandle> Abilities; // 能力句柄数组
		TArray<UAttributeSet*> Attributes; // 属性集数组
		TArray<FLyraAbilitySet_GrantedHandles> AbilitySetHandles; // 能力集句柄数组
	};

	/**
	 * 每个上下文的数据结构
	 */
	struct FPerContextData
	{
		TMap<AActor*, FActorExtensions> ActiveExtensions; // 活跃的扩展映射
		TArray<TSharedPtr<FComponentRequestHandle>> ComponentRequests; // 组件请求句柄数组
	};
	
	TMap<FGameFeatureStateChangeContext, FPerContextData> ContextData; // 上下文数据映射

	//~ 开始 UGameFeatureAction_WorldActionBase 接口
	virtual void AddToWorld(const FWorldContext& WorldContext, const FGameFeatureStateChangeContext& ChangeContext) override; // 添加到世界
	//~ 结束 UGameFeatureAction_WorldActionBase 接口

	void Reset(FPerContextData& ActiveData); // 重置数据
	void HandleActorExtension(AActor* Actor, FName EventName, int32 EntryIndex, FGameFeatureStateChangeContext ChangeContext); // 处理Actor扩展
	void AddActorAbilities(AActor* Actor, const FGameFeatureAbilitiesEntry& AbilitiesEntry, FPerContextData& ActiveData); // 添加Actor能力
	void RemoveActorAbilities(AActor* Actor, FPerContextData& ActiveData); // 移除Actor能力

	/**
	 * 查找或为Actor添加组件
	 */
	template<class ComponentType>
	ComponentType* FindOrAddComponentForActor(AActor* Actor, const FGameFeatureAbilitiesEntry& AbilitiesEntry, FPerContextData& ActiveData)
	{
		//@TODO: 只是查找，不添加？
		return Cast<ComponentType>(FindOrAddComponentForActor(ComponentType::StaticClass(), Actor, AbilitiesEntry, ActiveData));
	}
	UActorComponent* FindOrAddComponentForActor(UClass* ComponentType, AActor* Actor, const FGameFeatureAbilitiesEntry& AbilitiesEntry, FPerContextData& ActiveData); // 查找或添加组件
};